package com.yuno.mock.reader.impl;

import com.yuno.mock.dto.ExcelReadRequest;
import com.yuno.mock.dto.ExcelReadResult;
import com.yuno.mock.reader.ExcelReader;
import com.yuno.mock.strategy.ShardingStrategy;
import lombok.extern.slf4j.Slf4j;
import org.dhatim.fastexcel.reader.ReadableWorkbook;
import org.dhatim.fastexcel.reader.Row;
import org.dhatim.fastexcel.reader.Sheet;
import org.springframework.stereotype.Component;

import java.io.FileInputStream;
import java.io.InputStream;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionException;
import java.util.stream.Stream;

/**
 * FastExcel读取器实现
 * 使用FastExcel库实现高性能Excel文件读取
 * 
 * @author xrm
 * @since 1.0.0
 */
@Slf4j
@Component
public class FastExcelReader implements ExcelReader {
    
    private static final String READER_NAME = "FastExcelReader";
    private static final List<String> SUPPORTED_EXTENSIONS = Arrays.asList(".xlsx", ".xlsm");
    
    @Override
    public ExcelReadResult readExcel(ExcelReadRequest request) throws Exception {
        log.info("开始读取Excel文件: {}", request.getFilePath());
        
        long startTime = System.currentTimeMillis();
        ExcelReadResult result = new ExcelReadResult();
        result.setRequestId(request.getRequestId());
        result.setStartTime(LocalDateTime.now());
        
        try (InputStream inputStream = new FileInputStream(request.getFilePath());
             ReadableWorkbook workbook = new ReadableWorkbook(inputStream)) {
            
            // 获取工作表
            Sheet sheet = getSheet(workbook, request.getSheetName(), request.getSheetIndex());
            if (sheet == null) {
                throw new IllegalArgumentException("找不到指定的工作表");
            }
            
            // 读取数据
            List<List<Object>> data = readSheetData(sheet, request);
            
            // 构建结果
            result.setStatus("SUCCESS");
            result.setMessage("读取成功");
            result.setData(convertToMapList(data));
            result.setTotalRows((long) data.size());
            result.setTotalColumns(data.isEmpty() ? 0 : data.get(0).size());
            result.setSheetName(sheet.getName());
            result.setSheetIndex(Integer.parseInt(sheet.getId()));
            
            // 设置文件信息
            ExcelReadResult.FileInfo fileInfo = new ExcelReadResult.FileInfo();
            fileInfo.setFileName(extractFileName(request.getFilePath()));
            fileInfo.setFilePath(request.getFilePath());
            fileInfo.setFileSize(getFileSize(request.getFilePath()));
            result.setFileInfo(fileInfo);
            
            // 设置处理统计
            ExcelReadResult.ProcessingStats stats = new ExcelReadResult.ProcessingStats();
            stats.setThreadCount(1);
            stats.setShardCount(1);
            stats.setShardingStrategy("SINGLE");
            result.setProcessingStats(stats);
            
            result.setEndTime(LocalDateTime.now());
            
            log.info("Excel文件读取完成，共读取{}行数据，耗时{}ms", 
                    data.size(), System.currentTimeMillis() - startTime);
            
        } catch (Exception e) {
            log.error("读取Excel文件失败: {}", e.getMessage(), e);
            result.setStatus("ERROR");
            result.setMessage("读取失败: " + e.getMessage());
            
            ExcelReadResult.ErrorInfo errorInfo = new ExcelReadResult.ErrorInfo();
            errorInfo.setErrorCode("READ_ERROR");
            errorInfo.setErrorMessage(e.getMessage());
            errorInfo.setErrorDetail(getStackTrace(e));
            result.setErrors(Arrays.asList(errorInfo));
            
            throw e;
        }
        
        return result;
    }
    
    @Override
    public CompletableFuture<ExcelReadResult> readExcelAsync(ExcelReadRequest request) {
        return CompletableFuture.supplyAsync(() -> {
            try {
                return readExcel(request);
            } catch (Exception e) {
                throw new CompletionException(e);
            }
        });
    }
    
    @Override
    public ExcelReadResult readExcelShard(ExcelReadRequest request, ShardingStrategy.Shard shard) throws Exception {
        log.info("开始读取Excel分片: {} (行范围: {}-{})", 
                shard.getShardId(), shard.getStartRow(), shard.getEndRow());
        
        long startTime = System.currentTimeMillis();
        ExcelReadResult result = new ExcelReadResult();
        result.setRequestId(request.getRequestId());
        result.setStartTime(LocalDateTime.now());
        
        try (InputStream inputStream = new FileInputStream(request.getFilePath());
             ReadableWorkbook workbook = new ReadableWorkbook(inputStream)) {
            
            // 获取工作表
            Sheet sheet = getSheet(workbook, request.getSheetName(), request.getSheetIndex());
            if (sheet == null) {
                throw new IllegalArgumentException("找不到指定的工作表");
            }
            
            // 读取分片数据
            List<List<Object>> data = readShardData(sheet, request, shard);
            
            // 构建结果
            result.setStatus("SUCCESS");
            result.setMessage("分片读取成功");
            result.setData(convertToMapList(data));
            result.setTotalRows((long) data.size());
            result.setTotalColumns(data.isEmpty() ? 0 : data.get(0).size());
            result.setSheetName(sheet.getName());
            result.setSheetIndex(Integer.parseInt(sheet.getId()));
            
            // 设置处理统计
            ExcelReadResult.ProcessingStats stats = new ExcelReadResult.ProcessingStats();
            stats.setThreadCount(1);
            stats.setShardCount(1);
            stats.setShardingStrategy("SHARD");
            result.setProcessingStats(stats);
            
            result.setEndTime(LocalDateTime.now());
            
            log.info("Excel分片读取完成: {}，共读取{}行数据，耗时{}ms", 
                    shard.getShardId(), data.size(), System.currentTimeMillis() - startTime);
            
        } catch (Exception e) {
            log.error("读取Excel分片失败: {}", e.getMessage(), e);
            result.setStatus("ERROR");
            result.setMessage("分片读取失败: " + e.getMessage());
            
            ExcelReadResult.ErrorInfo errorInfo = new ExcelReadResult.ErrorInfo();
            errorInfo.setErrorCode("SHARD_READ_ERROR");
            errorInfo.setErrorMessage(e.getMessage());
            errorInfo.setErrorDetail(getStackTrace(e));
            result.setErrors(Arrays.asList(errorInfo));
            
            throw e;
        }
        
        return result;
    }
    
    @Override
    public Map<String, Object> getExcelInfo(String filePath) throws Exception {
        try (InputStream inputStream = new FileInputStream(filePath);
             ReadableWorkbook workbook = new ReadableWorkbook(inputStream)) {
            
            return buildExcelInfo(workbook, filePath);
        }
    }
    
    @Override
    public Map<String, Object> getExcelInfo(InputStream inputStream, String fileName) throws Exception {
        try (ReadableWorkbook workbook = new ReadableWorkbook(inputStream)) {
            return buildExcelInfo(workbook, fileName);
        }
    }
    
    @Override
    public long getRowCount(String filePath, String sheetName, Integer sheetIndex) throws Exception {
        try (InputStream inputStream = new FileInputStream(filePath);
             ReadableWorkbook workbook = new ReadableWorkbook(inputStream)) {
            
            Sheet sheet = getSheet(workbook, sheetName, sheetIndex);
            if (sheet == null) {
                throw new IllegalArgumentException("找不到指定的工作表");
            }
            
            // FastExcel需要遍历来计算行数
            try (Stream<Row> rows = sheet.openStream()) {
                return rows.count();
            }
        }
    }
    
    @Override
    public int getColumnCount(String filePath, String sheetName, Integer sheetIndex) throws Exception {
        try (InputStream inputStream = new FileInputStream(filePath);
             ReadableWorkbook workbook = new ReadableWorkbook(inputStream)) {
            
            Sheet sheet = getSheet(workbook, sheetName, sheetIndex);
            if (sheet == null) {
                throw new IllegalArgumentException("找不到指定的工作表");
            }
            
            // 读取第一行来确定列数
            try (Stream<Row> rows = sheet.openStream()) {
                Optional<Row> firstRow = rows.findFirst();
                if (firstRow.isPresent()) {
                    Row row = firstRow.get();
                    int maxColumn = 0;
                    for (int i = 0; i < 1000; i++) { // 限制检查范围
                        if (row.getCellText(i) != null && !row.getCellText(i).trim().isEmpty()) {
                            maxColumn = i;
                        }
                    }
                    return maxColumn + 1;
                }
            }
            
            return 0;
        }
    }
    
    @Override
    public boolean validateExcelFile(String filePath) {
        try {
            String fileName = extractFileName(filePath);
            if (!supports(fileName)) {
                return false;
            }
            
            try (InputStream inputStream = new FileInputStream(filePath);
                 ReadableWorkbook workbook = new ReadableWorkbook(inputStream)) {
                
                // 尝试获取第一个工作表
                List<Sheet> sheets = workbook.getSheets().collect(java.util.stream.Collectors.toList());
                return !sheets.isEmpty();
            }
        } catch (Exception e) {
            log.warn("验证Excel文件失败: {}", e.getMessage());
            return false;
        }
    }
    
    @Override
    public boolean validateExcelFile(InputStream inputStream, String fileName) {
        try {
            if (!supports(fileName)) {
                return false;
            }
            
            try (ReadableWorkbook workbook = new ReadableWorkbook(inputStream)) {
                List<Sheet> sheets = workbook.getSheets().collect(java.util.stream.Collectors.toList());
                return !sheets.isEmpty();
            }
        } catch (Exception e) {
            log.warn("验证Excel文件失败: {}", e.getMessage());
            return false;
        }
    }
    
    @Override
    public List<String> getSupportedExtensions() {
        return new ArrayList<>(SUPPORTED_EXTENSIONS);
    }
    
    @Override
    public String getReaderName() {
        return READER_NAME;
    }
    
    @Override
    public boolean supports(String fileName) {
        if (fileName == null || fileName.trim().isEmpty()) {
            return false;
        }
        
        String lowerFileName = fileName.toLowerCase();
        return SUPPORTED_EXTENSIONS.stream()
                .anyMatch(lowerFileName::endsWith);
    }
    
    /**
     * 获取工作表
     */
    private Sheet getSheet(ReadableWorkbook workbook, String sheetName, Integer sheetIndex) {
        List<Sheet> sheets = workbook.getSheets().collect(java.util.stream.Collectors.toList());
        
        if (sheetName != null && !sheetName.trim().isEmpty()) {
            // 按名称查找
            return sheets.stream()
                    .filter(sheet -> sheetName.equals(sheet.getName()))
                    .findFirst()
                    .orElse(null);
        } else if (sheetIndex != null && sheetIndex >= 0 && sheetIndex < sheets.size()) {
            // 按索引查找
            return sheets.get(sheetIndex);
        } else {
            // 返回第一个工作表
            return sheets.isEmpty() ? null : sheets.get(0);
        }
    }
    
    /**
     * 读取工作表数据
     */
    private List<List<Object>> readSheetData(Sheet sheet, ExcelReadRequest request) {
        List<List<Object>> data = new ArrayList<>();
        
        try (Stream<Row> rows = sheet.openStream()) {
            rows.forEach(row -> {
                int rowNum = row.getRowNum();
                
                // 检查行范围 - 修正行号从0开始的问题
                if (request.getStartRow() != null && request.getStartRow() > 0 && rowNum < request.getStartRow()) {
                    return;
                }
                if (request.getEndRow() != null && request.getEndRow() > 0 && rowNum > request.getEndRow()) {
                    return;
                }
                
                List<Object> rowData = readRowData(row, request);
                
                // 跳过空行
                if (request.getSkipEmptyRows() != null && request.getSkipEmptyRows() && isEmptyRow(rowData)) {
                    return;
                }
                
                data.add(rowData);
            });
        } catch (Exception e) {
            log.error("读取工作表数据时发生异常", e);
            throw new RuntimeException("读取工作表数据失败", e);
        }
        
        return data;
    }
    
    /**
     * 读取分片数据
     */
    private List<List<Object>> readShardData(Sheet sheet, ExcelReadRequest request, ShardingStrategy.Shard shard) {
        List<List<Object>> data = new ArrayList<>();
        
        try (Stream<Row> rows = sheet.openStream()) {
            rows.forEach(row -> {
                int rowNum = row.getRowNum();
                
                // 检查分片范围
                if (rowNum < shard.getStartRow() || rowNum > shard.getEndRow()) {
                    return;
                }
                
                List<Object> rowData = readRowData(row, request);
                
                // 跳过空行
                if (request.getSkipEmptyRows() != null && request.getSkipEmptyRows() && isEmptyRow(rowData)) {
                    return;
                }
                
                data.add(rowData);
            });
        } catch (Exception e) {
            log.error("读取分片数据时发生异常", e);
            throw new RuntimeException("读取分片数据失败", e);
        }
        
        return data;
    }
    
    /**
     * 读取行数据
     */
    private List<Object> readRowData(Row row, ExcelReadRequest request) {
        List<Object> rowData = new ArrayList<>();
        
        int startCol = Math.max(0, request.getStartColumn());
        int endCol = request.getEndColumn() > 0 ? request.getEndColumn() : 255; // 默认最大列数
        
        for (int colIndex = startCol; colIndex <= endCol; colIndex++) {
            String cellText = row.getCellText(colIndex);
            Object cellValue = parseCellValue(cellText, request, colIndex);
            
            // 跳过空列
            if (request.getSkipEmptyColumns() && (cellValue == null || cellValue.toString().trim().isEmpty())) {
                continue;
            }
            
            rowData.add(cellValue);
        }
        
        return rowData;
    }
    
    /**
     * 解析单元格值
     */
    private Object parseCellValue(String cellText, ExcelReadRequest request, int columnIndex) {
        if (cellText == null || cellText.trim().isEmpty()) {
            return null;
        }
        
        // 如果有数据类型映射，按指定类型解析
        if (request.getDataTypes() != null && request.getDataTypes().containsKey(columnIndex)) {
            String dataType = request.getDataTypes().get(columnIndex);
            return parseByDataType(cellText.trim(), dataType);
        }
        
        // 自动推断数据类型
        return autoParseValue(cellText.trim());
    }
    
    /**
     * 按指定数据类型解析
     */
    private Object parseByDataType(String value, String dataType) {
        try {
            return switch (dataType.toUpperCase()) {
                case "STRING" -> value;
                case "INTEGER" -> Integer.parseInt(value);
                case "LONG" -> Long.parseLong(value);
                case "DOUBLE" -> Double.parseDouble(value);
                case "BOOLEAN" -> Boolean.parseBoolean(value);
                case "DATE" -> parseDate(value);
                default -> value;
            };
        } catch (Exception e) {
            log.warn("解析数据类型失败: {} -> {}, 使用原始字符串", value, dataType);
            return value;
        }
    }
    
    /**
     * 自动解析值
     */
    private Object autoParseValue(String value) {
        // 尝试解析为数字
        try {
            if (value.contains(".")) {
                return Double.parseDouble(value);
            } else {
                long longValue = Long.parseLong(value);
                if (longValue >= Integer.MIN_VALUE && longValue <= Integer.MAX_VALUE) {
                    return (int) longValue;
                }
                return longValue;
            }
        } catch (NumberFormatException ignored) {
        }
        
        // 尝试解析为布尔值
        if ("true".equalsIgnoreCase(value) || "false".equalsIgnoreCase(value)) {
            return Boolean.parseBoolean(value);
        }
        
        // 默认返回字符串
        return value;
    }
    
    /**
     * 解析日期
     */
    private Object parseDate(String value) {
        // 这里可以添加更复杂的日期解析逻辑
        return value;
    }
    
    /**
     * 检查是否为空行
     */
    private boolean isEmptyRow(List<Object> rowData) {
        return rowData.stream()
                .allMatch(cell -> cell == null || cell.toString().trim().isEmpty());
    }
    
    /**
     * 构建Excel信息
     */
    private Map<String, Object> buildExcelInfo(ReadableWorkbook workbook, String fileName) {
        Map<String, Object> info = new HashMap<>();
        
        info.put("fileName", extractFileName(fileName));
        info.put("readerName", READER_NAME);
        info.put("fileType", "XLSX");
        
        List<Sheet> sheets = workbook.getSheets().collect(java.util.stream.Collectors.toList());
        info.put("sheetCount", sheets.size());
        
        List<Map<String, Object>> sheetInfos = new ArrayList<>();
        for (Sheet sheet : sheets) {
            Map<String, Object> sheetInfo = new HashMap<>();
            sheetInfo.put("name", sheet.getName());
            sheetInfo.put("index", sheet.getId());
            
            // 获取行数和列数需要遍历，这里暂时不计算以提高性能
            sheetInfo.put("rowCount", -1);
            sheetInfo.put("columnCount", -1);
            
            sheetInfos.add(sheetInfo);
        }
        info.put("sheets", sheetInfos);
        
        return info;
    }
    
    /**
     * 提取文件名
     */
    private String extractFileName(String filePath) {
        if (filePath == null) {
            return "";
        }
        int lastSeparator = Math.max(filePath.lastIndexOf('/'), filePath.lastIndexOf('\\'));
        return lastSeparator >= 0 ? filePath.substring(lastSeparator + 1) : filePath;
    }
    
    /**
     * 获取文件大小
     */
    private long getFileSize(String filePath) {
        try {
            return new java.io.File(filePath).length();
        } catch (Exception e) {
            return -1;
        }
    }
    
    /**
     * 将List<List<Object>>转换为List<Map<String, Object>>
     */
    private List<Map<String, Object>> convertToMapList(List<List<Object>> data) {
        if (data == null || data.isEmpty()) {
            return new ArrayList<>();
        }
        
        List<Map<String, Object>> result = new ArrayList<>();
        
        // 如果有表头，使用表头作为key
        List<Object> headers = data.get(0);
        boolean hasHeaders = headers != null && !headers.isEmpty();
        
        int startIndex = hasHeaders ? 1 : 0;
        
        for (int i = startIndex; i < data.size(); i++) {
            List<Object> row = data.get(i);
            Map<String, Object> rowMap = new HashMap<>();
            
            for (int j = 0; j < row.size(); j++) {
                String key;
                if (hasHeaders && j < headers.size()) {
                    key = headers.get(j) != null ? headers.get(j).toString() : "column_" + j;
                } else {
                    key = "column_" + j;
                }
                rowMap.put(key, row.get(j));
            }
            
            result.add(rowMap);
        }
        
        return result;
    }
    
    /**
     * 获取异常堆栈信息
     */
    private String getStackTrace(Exception e) {
        java.io.StringWriter sw = new java.io.StringWriter();
        java.io.PrintWriter pw = new java.io.PrintWriter(sw);
        e.printStackTrace(pw);
        return sw.toString();
    }
}